home *** CD-ROM | disk | FTP | other *** search
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
- /* |_o_o|\\ Copyright (c) 1986 The Software Distillery. All Rights Reserved */
- /* |. o.| || This program may not be distributed without the permission of */
- /* | . | || the authors. */
- /* | o | || Dave Baker Ed Burnette Stan Chow Jay Denebeim */
- /* | . |// Gordon Keener Jack Rouse John Toebes Doug Walker */
- /* ====== BBS:(919)-471-6436 VOICE:(919)-469-4210 */
- /* */
- /* Contributed to Columbia University for inclusion in C-Kermit. */
- /* Permission is granted to any individual or institution to use, copy, or */
- /* redistribute this software so long as it is not sold for profit, provided */
- /* this copyright notice is retained. */
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
- char *ckxv = "Amiga tty I/O $Id: ckitio.c,v 1.9 93/08/03 08:36:07 swalton Exp Locker: swalton $";
-
- /* C K I T I O -- Serial and Console I/O support for the Amiga */
-
- /*
- * Author: Jack Rouse, The Software Distillery
- * Based on the CKUTIO.C module for Unix
- *
- * Modified for Manx Aztec C and Version 1.2 and forward of Amiga's OS by
- * Stephen Walton of California State University, Northridge,
- * srw@csun.edu. Further mods documented in ckiker.upd.
- *
-
- $Log: ckitio.c,v $
- * Revision 1.9 93/08/03 08:36:07 swalton
- * Many changes thanks to Olaf Barthel:
- * 1. Changed include files to Amiga standard.
- * 2. Changed signal-handling to use ANSI signal() call. Still can't
- * call Aztec Chk_Abort(), though, because it ignores signal().
- * 3. Used GetScreenData() on the Workbench screen to find the window
- * size to open.
- * 4. Deleted DoIOQuick() and changed calls to it to DoIO(), which is
- * identical.
- * 5.. ttol() rewritten to have a static buffer whose size is checked
- * and to handle the pendwrite flag correctly.
- *
- * Revision 1.8 92/10/30 16:14:46 swalton
- * Put in code to attempt to open a 1024 by 1024 console, at John Ata's
- * suggestion. This will make a maximum-size window on most Amigas.
- *
- * Added code to set a global int "v37" to TRUE or FALSE according to the
- * version of the ROM Kernel. This is then used in other places to
- * conditionally turn on V37 features.
- *
- * Revision 1.7 92/03/16 13:50:58 swalton
- * Support added for CTR/RTS flow control, using the new FLO_ manifest
- * constants in version 5A.
- *
- * Revision 1.6 92/01/15 17:12:35 swalton
- * Added Long BREAK support with new ttsndlb() routine.
- *
- * Added support for multiple devices; the SET LINE command now takes a
- * line of the form "device/unit".
- *
- * Revision 1.5 91/07/18 16:04:57 swalton
- * ttinl() now null terminates a received packet correctly.
- *
- * Revision 1.4 91/05/29 09:08:57 swalton
- * 1. Changed function definitions to prototype style. Required adding
- * a few forward declarations.
- * 2. Removed includes of stdio.h, stdlib.h, and string.h, as they are
- * now pulled in by ckcdeb.h, provided we compile with -DCK_ANSILIBS.
- *
- * Revision 1.3 90/11/19 21:46:54 swalton
- * Modifications for compiling with SAS/C Version 5.10, courtesy of
- * Larry Rosenman (ler@erami.lonestar.org, ler on BIX)
- *
- * Revision 1.2 90/11/07 14:42:07 swalton
- * Version 1.2--released to world as first beta test version simultaneously
- * with release of edit 5A(160).
- *
- * Revision 1.1 90/07/12 22:30:11 swalton
- * Rather extensive changes were made to ckitio.c, mainly to add new functions
- * required for the proper operation of C Kermit 5A(149). They are not listed
- * in detail here; refer to the parts of the C Kermit interface document
- * (file ckasys.doc in the Kermit archive) for the portions labeled *NEW*.
- * These will point you at the code revisions.
- *
- * Revision 1.0 90/04/30 11:54:27 swalton
- * Initial revision
- *
- */
-
- #include "ckcdeb.h"
- #include "ckcker.h"
- #include "ckcnet.h"
- #include <exec/types.h>
- #include <exec/exec.h>
- #include <devices/serial.h>
- #include <devices/timer.h>
- #include <libraries/dos.h>
- #include <libraries/dosextens.h>
- #define fh_Interact fh_Port
- #define fh_Process fh_Type
- #include <intuition/intuition.h>
- #include <intuition/intuitionbase.h>
- #define BREAKSIGS (SIGBREAKF_CTRL_C|SIGBREAKF_CTRL_D)
- #include <string.h>
- #ifdef AZTEC_C
- #include <fcntl.h>
- #include <signal.h>
- char *ckxsys = " Commodore Amiga (Aztec_C)"; /* system name */
- #else
- #ifdef __SASC
- #include <fcntl.h>
- #include <signal.h>
- #include <ios1.h> /* defines ufbs structure */
- char *ckxsys = " Commodore Amiga (SAS/C)"; /* system name */
- #endif
- #endif
-
- #include <clib/exec_protos.h>
- #include <clib/alib_protos.h>
- #include <clib/dos_protos.h>
- #include <clib/intuition_protos.h>
-
- /* external definitions */
- char *dftty = SERIALNAME; /* serial device name */
- int dfloc = 1; /* serial line is external */
- int dfprty = 0; /* default parity is none */
- int ttprty = 0; /* parity in use */
- int dfflow = FLO_XONX; /* default flow control is on */
- int backgrd = 0; /* default to foreground */
- int ckxech = 0; /* echo in case redirected stdin */
- int tvtflg = 0; /* Flag for ttvt() called. */
- int ttcarr = 0; /* Carrier detection mode */
- int ttnproto = NP_NONE; /* Protocol for network device */
-
- struct Process *CurProc; /* current process */
- struct CommandLineInterface *CurCLI; /* current CLI info */
- struct IntuitionBase *IntuitionBase; /* ptr to Intuition lib */
- short v37; /* Are we version 37? */
-
- /* static definitions */
- static struct MsgPort *serport; /* message port for serial comm */
- static struct MsgPort *conport; /* console packet port */
- static struct timerequest *TimerIOB; /* timer request */
- static struct IOExtSer *ReadIOB; /* serial input request */
- static struct IOExtSer *WriteIOB; /* serial output request */
- static struct DosPacket *conpkt; /* console I/O packet */
- static WORD serialopen; /* true iff serial device open */
- static WORD timeropen; /* true iff timer device open */
- static WORD pendwrite; /* true iff WriteIOB in use */
- static WORD pendread; /* true iff ReadIOB in use */
- static WORD pendconsole; /* true when console read pending */
- static int queuedser; /* serial pushback char or -1 */
- static UBYTE serbufc; /* char buffer for read ahead I/O */
- #define NTTOQ 64 /* connect output queue size */
- static char ttoq[NTTOQ]; /* connect output queue */
- static int nttoq; /* number of chars in ttoq */
- static int pttoq; /* next char to output in ttoq */
- static int queuedcon; /* contti pushback char or -1 */
- static LONG intsigs; /* signals for aborting serial I/O */
- static BPTR rawcon; /* file handle for RAW: window */
- static BPTR saverr; /* saved stderr file handle */
- static APTR savewindow; /* saved process WindowPtr */
- static APTR pushwindow; /* pushed process WindowPtr */
- static struct DateStamp prevtime; /* saved time value */
-
-
- /* AmigaDOS support (from ckiutl.c) */
- struct DosPacket *CreatePacket(void);
- VOID DeletePacket(struct DosPacket *);
-
- #ifdef AZTEC_C
- /* translate Unix file handle (0, 1, or 2) to AmigaDOS file handle */
- #define DOSFH(n) (_devtab[n].fd)
- /* translate Unix file handle (0, 1, or 2) to Aztec file handle */
- #define FILENO(n) (n)
- extern int Enable_Abort;
- #else
- /* Lattice runtime externals */
- #ifdef __SASC
- #define DOSFH(n) (chkufb(n)->ufbfh)
- #define FILENO(n) (n)
- #endif
- #endif
-
- /*
- * Under ANSI C, pointer-pointer assignments are illegal without an
- * explicit cast. So, we define the following to make such casts short.
- */
- #define IOR struct IORequest
-
- /*
- * Forward declarations
- */
- void reqres(void);
- static void testint(long);
- #ifdef AZTEC_C
- #define Chk_Abort() testint(0L)
- #else
- void Chk_Abort(void); /* or #define Chk_Abort() testint(0) */
- #endif
-
- /*
- * make note of a serial error and quit
- */
- static void
- Fail(char *msg)
- {
- syscleanup();
- fprintf(stderr, msg);
- fprintf(stderr, "\n");
- exit(2);
- }
-
- void
- emergency(void) {
- (void) syscleanup();
- }
-
- /*
- * sysinit -- Amiga specific initialization
- */
- int
- sysinit(void)
- {
- struct IOExtSer *iob;
-
- /* set current process info */
- CurProc = (struct Process *)FindTask((char *)NULL);
- CurCLI = (struct CommandLineInterface *)BADDR(CurProc->pr_CLI);
- backgrd = (CurCLI == NULL || CurCLI->cli_Background);
- savewindow = CurProc->pr_WindowPtr;
-
- signal(SIGINT, SIG_IGN);
-
- /* allocate console ports and IO blocks */
- if ((conport = CreatePort((char *)NULL, 0L)) == NULL)
- Fail("no console MsgPort");
- if ((conpkt = CreatePacket()) == NULL)
- Fail("no console packet");
-
- /* allocate serial ports and IO blocks */
- if ((serport = CreatePort((char *)NULL, 0L)) == NULL)
- Fail("no serial MsgPort");
- iob = (struct IOExtSer *)CreateExtIO(serport,(LONG)sizeof(*iob));
- if ((WriteIOB = iob) == NULL) Fail("no WriteIOB");
- iob = (struct IOExtSer *)CreateExtIO(serport,(LONG)sizeof(*iob));
- if ((ReadIOB = iob) == NULL) Fail("no ReadIOB");
-
- /* open the timer device */
- TimerIOB = (struct timerequest *)
- CreateExtIO(serport,(LONG)sizeof(*TimerIOB));
- if (TimerIOB == NULL) Fail("no TimerIOB");
- if (OpenDevice(TIMERNAME, (LONG)UNIT_VBLANK, (IOR *)TimerIOB, 0L) != 0)
- Fail("no timer device");
- timeropen = TRUE;
-
- /* open the Intuition library */
- if (!IntuitionBase &&
- (IntuitionBase = (struct IntuitionBase *)
- OpenLibrary("intuition.library", 0L) ) == NULL )
- Fail("can't open Intuition");
-
- if (((struct Library *)IntuitionBase)->lib_Version >= 37)
- v37 = TRUE;
- else
- v37 = FALSE;
- /* open the serial device to get configuration */
- iob->io_SerFlags = SERF_SHARED;
- if (OpenDevice(SERIALNAME, 0L, (IOR *)iob, 0L) != 0)
- Fail("can't open serial.device");
- /* set parameters from system defaults */
- if (!(iob->io_SerFlags & SERF_XDISABLED))
- dfflow = FLO_XONX;
- else if (iob->io_SerFlags & SERF_7WIRE)
- dfflow = FLO_RTSC;
- else
- dfflow = FLO_NONE;
- /*
- * Set default (startup) parity from Preferences settings.
- */
- if (iob->io_SerFlags & SERF_PARTY_ON) /* Parity is on */
- if (iob->io_ExtFlags & SEXTF_MSPON) /* Space or mark */
- if (iob->io_ExtFlags & SEXTF_MARK)
- dfprty = 'm'; /* Mark parity */
- else
- dfprty = 's'; /* Space parity */
- else /* Even or odd */
- if (iob->io_SerFlags & SERF_PARTY_ODD)
- dfprty = 'o'; /* Odd parity */
- else
- dfprty = 'e'; /* Even parity */
- else
- dfprty = 0; /* No parity. */
- ttprty = dfprty;
-
- CloseDevice((IOR *)iob);
- serialopen = FALSE;
- atexit(emergency);
- return(0);
- }
-
- /*
- * syscleanup -- Amiga specific cleanup
- */
- syscleanup(void)
- {
- /* close everything */
- if (serialopen) CloseDevice((IOR *)ReadIOB);
- if (timeropen) CloseDevice((IOR *)TimerIOB);
- if (TimerIOB) DeleteExtIO((IOR *)TimerIOB);
- if (WriteIOB) DeleteExtIO((IOR *)WriteIOB);
- if (ReadIOB) DeleteExtIO((IOR *)ReadIOB);
- if (serport) DeletePort(serport);
- if (conpkt) DeletePacket(conpkt);
- if (conport) DeletePort(conport);
- reqres();
- if (IntuitionBase)
- {
- CloseLibrary((struct Library *)IntuitionBase);
- IntuitionBase = NULL;
- }
-
- /* reset standard I/O */
- if (rawcon > 0)
- {
- /* restore Lattice AmigaDOS file handles */
- DOSFH(0) = Input();
- DOSFH(1) = Output();
- DOSFH(2) = saverr;
- Close(rawcon);
- }
- serialopen = timeropen = 0;
- TimerIOB = WriteIOB = ReadIOB = serport = conpkt = conport = NULL;
- IntuitionBase = NULL;
- rawcon = 0;
- return 1;
- }
-
- /*
- * reqoff -- turn requestors off
- * When AmigaDOS encounters an error that user intervention can fix
- * (like inserting the correct disk), it normally puts up a requestor.
- * The following code disables requestors, causing an error to be
- * returned instead.
- */
- void
- reqoff(void)
- {
- pushwindow = CurProc->pr_WindowPtr;
- CurProc->pr_WindowPtr = (APTR)-1;
- }
- /*
- * reqpop -- restore requesters to action at last reqoff
- */
- void
- reqpop(void)
- {
- CurProc->pr_WindowPtr = pushwindow;
- }
-
- /*
- * reqres -- restore requestors to startup action
- */
- void
- reqres(void)
- {
- CurProc->pr_WindowPtr = savewindow;
- }
-
- /*
- * KillIO -- terminate an I/O request
- */
- static int
- KillIO(struct IORequest *iob)
- {
- AbortIO(iob);
- return((int)WaitIO(iob));
- }
-
- /*
- * ttopen -- open the serial device
- * If already open, returns 0 immediately.
- * Otherwise, the ttname is compare to SERIALNAME and used to
- * open the serial device, and, if the value of *lcl is < 0, it is
- * reset to 1 indicating local mode. Returns -1 on error.
- * timo is the length of time to wait before flunking open; we don't
- * need this feature on the Amiga.
- */
- int
- ttopen(char * ttname, int *lcl, int modem, int timo)
- {
- struct IOExtSer *iob = ReadIOB;
- char *p;
- ULONG unit;
- static char cttname[50]; /* Current open ttname */
-
- if (modem < 0) return -1; /* We don't do networks yet. */
- if (serialopen) /* Already have serial device open */
- if (strcmp(ttname, cttname) == 0)
- return(0); /* Same device - ignore */
- else ttclos(0); /* Different device - close */
-
- /* verify the serial name */
- #if 0
- if (strcmp(ttname, SERIALNAME) != 0) return(-1);
- #endif
-
- /* set open modes. We no longer open in shared mode. */
- iob->io_SerFlags = (modem > 0 ? SERF_7WIRE : 0);
-
- /* parse device name as device/unit */
- if ((p = strchr(ttname, '/')) == NULL)
- unit = 0;
- else {
- if (*(p + strlen(p) - 1) == 's') /* Open in shared mode */
- {
- iob->io_SerFlags |= SERF_SHARED;
- *(p + strlen(p) - 1) = '\0';
- }
- unit = (ULONG) atoi(p + 1);
- *p = '\0';
- }
- /* open the serial device */
- if (OpenDevice(ttname, unit, (IOR *)iob, 0L) != 0)
- return(-1);
- serialopen = TRUE;
- tvtflg = 0;
- pendread = pendwrite = pendconsole = FALSE;
- queuedser = -1;
-
- /* fill in the fields of the other IO blocks */
- *WriteIOB = *iob;
-
- /* set local mode */
- if (*lcl == -1) *lcl = 1; /* always local */
- if (p) *p = '/'; /* restore slash */
- if (iob->io_SerFlags & SERF_SHARED)
- *(p + strlen(p)) = 's'; /* restore suffix if present */
- strcpy(cttname, ttname);
- return(0);
- }
-
- /*
- * StartTimer -- start a timeout
- */
- static VOID
- StartTimer(LONG secs, LONG micro)
- {
- TimerIOB->tr_node.io_Command = TR_ADDREQUEST;
- TimerIOB->tr_time.tv_secs = secs;
- TimerIOB->tr_time.tv_micro = micro;
- SendIO((IOR *)TimerIOB);
- }
-
- /*
- * SerialWait -- wait for serial I/O to terminate
- * return I/O error
- */
- static int
- SerialWait(struct IOExtSer *iob, int timeout)
- {
- LONG sigs;
- struct timerequest *timer = TimerIOB;
- LONG waitsigs;
-
- /* set up timeout if necessary */
- if (timeout > 0) StartTimer((LONG)timeout, 0L);
-
- /* wait for completion, timeout, or interrupt */
- sigs = 0;
- waitsigs = (1L << serport->mp_SigBit) | intsigs;
- for (;;)
- {
- if (sigs & intsigs)
- { /* interrupted */
- if (timeout > 0) KillIO((IOR *)timer);
- KillIO((IOR *)iob);
- testint(sigs);
- return(-1);
- }
- if (CheckIO((IOR *)iob))
- {
- if (timeout > 0) KillIO((IOR *)timer);
- return((int)WaitIO((IOR *)iob));
- }
- if (timeout > 0 && CheckIO((IOR *)timer))
- {
- KillIO((IOR *)iob);
- WaitIO((IOR *)timer);
- /* restart if XOFF'ed */
- iob->IOSer.io_Command = CMD_START;
- DoIO((IOR *)iob);
- return(-1);
- }
- sigs = Wait(waitsigs);
- }
- }
-
- /*
- * TerminateRead -- wait for queued read to finish
- */
- static int
- TerminateRead(void)
- {
- if (!pendread) return(0);
- if (WaitIO((IOR *)ReadIOB) == 0) queuedser = serbufc;
- pendread = FALSE;
- return((int)ReadIOB->IOSer.io_Error);
- }
-
- /*
- * TerminateWrite -- ensure WriteIOB is ready for reuse
- */
- static int
- TerminateWrite(int timeout)
- {
- Chk_Abort();
- if (!pendwrite) return(0);
- pendwrite = FALSE;
- if (timeout) {
- timeout = WriteIOB->IOSer.io_Length * 80 / WriteIOB->io_Baud;
- }
- return(SerialWait(WriteIOB, timeout));
- }
-
- /*
- * SerialReset -- terminate pending serial and console I/O
- */
- static void
- SerialReset(void)
- {
- if (pendread)
- {
- AbortIO((IOR *)ReadIOB); /* should work even if read finished */
- TerminateRead();
- }
-
- if (pendconsole)
- { /* this does not happen normally */
- WaitPort(conport);
- GetMsg(conport);
- pendconsole = FALSE;
- }
-
- if (pendwrite)
- TerminateWrite(1);
- }
-
- /*
- * ttres -- reset serial device
- */
- ttres()
- {
- if (!serialopen) return(-1);
-
- /* reset everything */
- SerialReset();
- ReadIOB->IOSer.io_Command = CMD_RESET;
- tvtflg = 0;
- return(DoIO((IOR *)ReadIOB) ? -1 : 0);
- }
-
- /*
- * ttclos -- close the serial device
- */
- int
- ttclos(int foo)
- {
- if (!serialopen) return(0);
- if (ttres() < 0) return(-1);
- CloseDevice((IOR *)ReadIOB);
- serialopen = FALSE;
- tvtflg = 0;
- return(0);
- }
-
- /*
- * tthang -- hang up phone line
- * Drops DTR by closing serial.device
- */
- int
- tthang(void)
- {
- return((serialopen) ? ttclos(0) : -1);
- }
-
- /*
- * ttpkt -- set serial device up for packet transmission
- * sets serial parameters
- */
- int
- ttpkt(long speed, int flow, int parity)
- {
- extern UBYTE eol;
- struct IOExtSer *iob = ReadIOB;
-
- if (!serialopen || pendread) return(-1);
-
- /* terminate any pending writes */
- TerminateWrite(1);
-
- /* fill in parameters */
- iob->io_CtlChar = 0x11130000;
- if (speed >= 0 && ttsspd((int) (speed / 10)) >= 0) iob->io_Baud = speed;
- iob->io_RBufLen = speed; /* 10 seconds worth of data */
- /*
- * Notice the dopar(eol) here to set the EOL character with the
- * appropriate parity. See also ttinl().
- */
- memset(&iob->io_TermArray, dopar(eol), sizeof(struct IOTArray));
- iob->io_ReadLen = iob->io_WriteLen = 8;
- iob->io_StopBits = 1;
- if (flow == FLO_XONX)
- iob->io_SerFlags &= ~(SERF_XDISABLED | SERF_7WIRE);
- else if (flow == FLO_NONE) {
- iob->io_SerFlags |= SERF_XDISABLED;
- iob->io_SerFlags &= ~SERF_7WIRE;
- } else if (flow == FLO_RTSC)
- iob->io_SerFlags |= (SERF_XDISABLED | SERF_7WIRE);
- else {
- puts("Only XON/XOFF and RTS/CTS are available");
- iob->io_SerFlags |= SERF_XDISABLED;
- iob->io_SerFlags &= ~SERF_7WIRE;
- }
- /* if no XON/XOFF flow and high baud rate, RAD_BOOGIE is appropriate */
- if (flow != FLO_XONX && iob->io_Baud >= 19200)
- iob->io_SerFlags |= SERF_RAD_BOOGIE;
- else
- iob->io_SerFlags &= ~SERF_RAD_BOOGIE;
-
- /*
- * Parity setting. For packet send/receive, we turn off the
- * Amiga's internal parity generation and checking, as this code
- * does it itself (which makes it bigger and slower...). We
- * save the current parity for ttinl().
- */
-
- ttprty = parity;
- iob->io_SerFlags &= ~(SERF_EOFMODE|SERF_PARTY_ON|SERF_PARTY_ODD);
- iob->io_ExtFlags = 0; /* MUST BE ZERO unless Mark or Space. */
-
- /* set the parameters */
- iob->IOSer.io_Command = SDCMD_SETPARAMS;
- if (DoIO((IOR *)iob) != 0) return(-1);
- tvtflg = 0;
- return(ttflui());
- }
-
- /*
- * ttvt -- set up serial device for connect mode. This is almost the same
- * as ttpkt() on the Amiga, except we save the settings and a flag and return
- * without doing anything if we've already been called with the same
- * values.
- */
- int
- ttvt(long speed, int flow) {
- static long ospeed = -1;
- static int oflow = -9;
-
- if (tvtflg != 0 && ospeed == speed && oflow == flow)
- return 0;
- if (ttpkt(speed, flow, 0) < 0)
- return -1;
- ospeed = speed; /* Save speed */
- oflow = flow; /* and flow control set */
- tvtflg = 1; /* and flag we've been called */
- return 0;
- }
-
- /* T T S S P D -- Checks and sets transmission rate. */
-
- /* Call with speed in characters (not bits!) per second. */
- /* Returns 0 if successful, -1 otherwise. */
-
- int
- ttsspd(int cps) {
- #ifdef NETCONN
- if (netconn) return (0);
- #endif /* NETCONN */
-
- if (cps <= 0) return(-1);
-
- /* First check that the given speed is valid. */
- /* 888 means 75/1200 split speed */
- if (cps == 888 || cps < 11) {
- return -1;
- }
-
- return cps;
- }
-
- /* T T G S P D - Get speed of currently selected tty line */
-
- /*
- Read speed from serial.device, or, if not open, return the value in
- the current ReadIOB.
- */
- long
- ttgspd(void) { /* Get current tty speed */
- struct IOExtSer *myread = ReadIOB;
-
- if (!serialopen)
- if (myread != NULL) return((long)myread->io_Baud);
- else return -1;
- Chk_Abort();
- if (pendread && !CheckIO((IOR *)myread)) return(0);
- if (TerminateRead() != 0) return(-1);
- myread->IOSer.io_Command = SDCMD_QUERY;
- return((DoIO((IOR *)myread) == 0)
- ? (long)myread->io_Baud
- : -1);
- }
-
- /*
- * ttflui -- flush serial device input buffer
- */
- int
- ttflui(void)
- {
- if (!serialopen || pendread) return(-1);
- queuedser = -1;
- ReadIOB->IOSer.io_Command = CMD_CLEAR;
- return(DoIO((IOR *)ReadIOB) ? -1 : 0);
- }
-
- /*
- * ttfluo -- flush serial output buffer
- */
- int
- ttfluo(void)
- {
- if (!serialopen || pendwrite) return -1;
- WriteIOB->IOSer.io_Command = CMD_CLEAR;
- return(DoIO((IOR *)WriteIOB) ? -1 : 0);
- }
-
-
- /*
- * test for and catch interrupt
- */
- static void
- testint(LONG sigs)
- {
- /* test for and reset caught interrupt signals */
- if ((sigs | SetSignal(0L, (LONG)BREAKSIGS)) & intsigs) {
- raise(SIGINT);
- }
- }
-
- /*
- * conint -- set console interrupt handler and suspend handler.
- */
- void
- conint(SIGTYP (*newhdlr)(int), SIGTYP (*stophdlr)(int))
- {
- Chk_Abort(); /* handle any pending interrupts */
- signal(SIGINT, newhdlr); /* set the new handler */
- intsigs = BREAKSIGS; /* note signal caught */
- }
-
- /*
- * connoi -- disable interrupt trapping
- */
- void
- connoi(void)
- {
- signal(SIGINT, SIG_IGN); /* disable interrupts */
- intsigs = 0; /* note signal ignored */
- Chk_Abort(); /* ignore pending interrupts */
- }
-
- /*
- * ttchk -- return number of chars immediately available from serial device
- */
- int
- ttchk(void)
- {
- struct IOExtSer *myread = ReadIOB;
-
- if (!serialopen) return(-1);
- Chk_Abort();
- if (pendread && !CheckIO((IOR *)myread)) return(0);
- if (TerminateRead() != 0) return(-1);
- myread->IOSer.io_Command = SDCMD_QUERY;
- return((DoIO((IOR *)myread) == 0)
- ? ((queuedser >= 0 ? 1 : 0) + (int)myread->IOSer.io_Actual)
- : -1);
- }
-
- /*
- * ttxin -- get n characters from serial device. This routine should
- * only be called when we know that there are at least n characters
- * ready to be read.
- */
- int
- ttxin(int n, CHAR *buf)
- {
- return(ttinl(buf, n, 0, 0));
- }
-
- #ifdef PARSENSE
-
- extern CHAR partab[];
-
- /* P A R C H K -- Check if Kermit packet has parity */
-
- /*
- Call with s = pointer to packet, start = packet start character, n = length.
- Returns 0 if packet has no parity, -1 on error, or if packet has parity:
- 'e' for even, 'o' for odd, 'm' for mark. Space parity cannot be sensed.
- */
- parchk(s,start,n) CHAR *s, start; int n; {
- CHAR s0, s1, s2, s3, sn;
-
- debug(F101,"parchk n","",n);
- debug(F101,"parchk start","",start);
- debug(F110,"parchk s",s,0);
-
- s0 = s[0] & 0x7f; /* Mark field (usually Ctrl-A) */
-
- if (s0 != start || n < 5) return(-1); /* Not a valid packet */
-
- /* Look at packet control fields, which never have 8th bit set */
- /* First check for no parity, most common case. */
-
- if (((s[0] | s[1] | s[2] | s[3] | s[n-2]) & 0x80) == 0)
- return(0); /* No parity */
-
- /* Check for mark parity */
-
- if (((s[0] & s[1] & s[2] & s[3] & s[n-2]) & 0x80) == 0x80)
- return('m'); /* Mark parity */
-
- /* Packet has some kind of parity */
- /* Make 7-bit copies of control fields */
-
- s1 = s[1] & 0x7f; /* LEN */
- s2 = s[2] & 0x7f; /* SEQ */
- s3 = s[3] & 0x7f; /* TYPE */
- sn = s[n-2] & 0x7f; /* CHECK */
-
- /* Check for even parity */
-
- if ((s[0] == partab[s0]) &&
- (s[1] == partab[s1]) &&
- (s[2] == partab[s2]) &&
- (s[3] == partab[s3]) &&
- (s[n-2] == partab[sn]))
- return('e');
-
- /* Check for odd parity */
-
- if ((s[0] != partab[s0]) &&
- (s[1] != partab[s1]) &&
- (s[2] != partab[s2]) &&
- (s[3] != partab[s3]) &&
- (s[n-2] != partab[sn]))
- return('o');
-
- /* Otherwise it's probably line noise. Let checksum calculation catch it. */
-
- return(-1);
- }
- #endif /* PARSENSE */
-
- /*
- * ttinc -- read character from serial line
- */
- int
- ttinc(int timeout)
- {
- UBYTE ch;
-
- return((ttinl((CHAR *)&ch, 1, timeout, 0) > 0) ? (int)ch : -1);
- }
-
- /*
- * ttol -- write n chars to serial device. For small writes, we have
- * a small local buffer which allows them to run asynchronously. For
- * large writes, we do them synchronously. This seems to be the best
- * compromise between speed and code simplicity and size.
- *
- * Stephen Walton, 23 October 1989
- */
- int
- ttol(CHAR *buf, int n)
- {
- struct IOExtSer *mywrite = WriteIOB;
- static char outbuf[1024]; /* safe place for output characters */
- int s;
- int oldn = n;
-
- if (!serialopen) return(-1);
- if ((s = n - sizeof(outbuf)) > 0) {
- if (TerminateWrite(1) != 0) return(-1);
- mywrite->IOSer.io_Command = CMD_WRITE;
- mywrite->IOSer.io_Data = (APTR) buf;
- mywrite->IOSer.io_Length = s;
- SendIO((IOR *)mywrite);
- pendwrite = TRUE;
- buf += s;
- n -= s;
- memcpy(outbuf, buf, n);
- if (TerminateWrite(1) != 0) return(-1);
- } else {
- if (TerminateWrite(1) != 0) return(-1);
- memcpy(outbuf, buf, n);
- }
- mywrite->IOSer.io_Command = CMD_WRITE;
- mywrite->IOSer.io_Data = (APTR)outbuf;
- mywrite->IOSer.io_Length = n;
- SendIO((IOR *)mywrite);
- pendwrite = TRUE;
-
- return oldn;
- }
-
- /*
- * ttoc -- output single character to serial device
- */
- int
- ttoc(char c)
- {
- return(ttol((CHAR *) &c, 1));
- }
-
- /*
- * ttinl -- read from serial device, possibly with timeout and eol character
- * reads up to n characters, returning the number of characters read
- * if eol > 0, reading the eol character will terminate read
- * if timeout > 0, terminates read if timeout elapses
- * returns -1 on error, such as timeout or interrupt
- *
- * Note that this is the single routine which does all character reading
- * in Amiga C Kermit, and has some added "features" compared to, say,
- * the Unix version. If timeout is 0, this routine waits forever.
- * If eol is zero, it is not used.
- *
- * New for 5A(157) is the start parameter, which is the start-of-packet
- * character. Following the Unix example, we just read until eol,
- * but return a bad packet if the first character we got doesn't agree
- * with start.
- */
- int
- ttinl(CHAR *buf, int n, int timeout, CHAR eol)
- {
- unsigned mask;
- struct IOExtSer *myread = ReadIOB;
- int count;
- int nread, i;
-
- Chk_Abort();
- if (!serialopen || pendread || n <= 0) return(-1);
-
- mask = (ttprty ? 0177 : 0377); /* parity stripping mask */
-
- /* handle pushback */
- if (queuedser >= 0)
- {
- *buf = queuedser & mask; /* Strip queued character. */
- queuedser = -1;
- if (*buf == eol || n == 1) return(1);
- ++buf;
- --n;
- count = 1;
- }
- else
- count = 0;
-
- /* set up line terminator */
- if (eol > 0)
- {
- /*
- * For reasons which are obscure to me, this batch of
- * code generally fails. Normally, this doesn't matter,
- * because io_TermArray is set in ttpkt() above, and so
- * this code is only executed if eol changes as a result
- * of the initial packet negotiation. I found the bug
- * by inadvertently not using dopar(eol) in the setting
- * of io_TermArray in ttpkt(), which did cause this code
- * to be called if parity was MARK or EVEN (since in that
- * case dopar(eol) != eol).
- */
-
- if (dopar(eol) != *(UBYTE *)&myread->io_TermArray)
- {
- memset(&myread->io_TermArray, dopar(eol),
- sizeof(struct IOTArray));
- myread->IOSer.io_Command = SDCMD_SETPARAMS;
- if (DoIO((IOR *)myread) != 0) {
- debug(F111, "SETPARAMS fails in ttinl()",
- "io_Error", (int) myread->IOSer.io_Error);
- myread->io_TermArray.TermArray0 =
- myread->io_TermArray.TermArray1 = 0xffffffffu;
- return -1;
- }
- }
- myread->io_SerFlags |= SERF_EOFMODE;
- }
- else
- myread->io_SerFlags &= ~SERF_EOFMODE;
-
- /* set up the read */
- myread->IOSer.io_Command = CMD_READ;
- myread->IOSer.io_Data = (APTR)buf;
- myread->IOSer.io_Length = n;
-
- /* perform read quickly if possible */
- myread->IOSer.io_Flags = IOF_QUICK;
- BeginIO((IOR *)myread);
- if (myread->IOSer.io_Flags & IOF_QUICK)
- myread->IOSer.io_Flags = 0;
- else
- /* wait for read to complete if no QUICK. */
- if (SerialWait(myread, timeout) != 0)
- return -1;
-
- if (myread->IOSer.io_Error != 0)
- return -1;
- #if COMMENT
- if (start != 0 && (buf[0] & mask) != start) /* Bad packet */
- return -1;
- #endif
- /* Strip parity bits if need be. */
- nread = (int) myread->IOSer.io_Actual;
- if (ttprty)
- for (i = 0; i < nread; i++)
- buf[i] &= mask;
- if (nread > 1)
- buf[nread] = '\0'; /* Null terminate */
- return(count + nread);
- }
-
- /*
- * Sleeper -- perform an interruptible timeout
- */
- static int
- Sleeper(LONG secs, LONG micro)
- {
- LONG sigs;
- LONG waitsigs;
- struct timerequest *timer = TimerIOB;
-
- if (!timeropen) return(-1);
- StartTimer(secs, micro);
- sigs = 0;
- waitsigs = (1L << serport->mp_SigBit) | intsigs;
- for (;;)
- {
- if (CheckIO((IOR *)timer))
- {
- WaitIO((IOR *)timer);
- return(0);
- }
- if (sigs & intsigs)
- {
- KillIO((IOR *)timer);
- testint(sigs);
- return(-1);
- }
- sigs = Wait(waitsigs);
- }
- }
-
- /*
- * sleep -- wait n seconds
- */
- int
- sleep(int n)
- { return(Sleeper((LONG)n, 0L)); }
-
- /*
- * msleep -- wait n milliseconds
- */
- int
- msleep(int m)
- { return(Sleeper((LONG)(m / 1000), (m % 1000) * 1000L)); }
-
-
- /*
- * rtimer -- reset elapsed time
- */
- void
- rtimer(void)
- { DateStamp(&prevtime); }
-
- /*
- * gtimer -- get currently elapsed time in seconds
- */
- int
- gtimer(void)
- {
- int x;
- struct DateStamp curtime;
-
- DateStamp(&curtime);
- x = ((curtime.ds_Days - prevtime.ds_Days ) * 1440 +
- (curtime.ds_Minute - prevtime.ds_Minute) ) * 60 +
- (curtime.ds_Tick - prevtime.ds_Tick ) / 50;
- return((x < 0) ? 0 : x );
- }
-
- /*
- * ztime -- format current date and time into string
- */
- void
- ztime(char **s)
- {
- /*
- * The following date code taken from a USENET article by
- * Tomas Rokicki(rokicki@Navajo.ARPA)
- */
- static char *months[] = { NULL,
- "January","February","March","April","May","June",
- "July","August","September","October","November","December"};
- static char buf[32];
-
- long n ;
- int m, d, y ;
- struct DateStamp datetime;
-
- DateStamp(&datetime);
-
- n = datetime.ds_Days - 2251 ;
- y = (4 * n + 3) / 1461 ;
- n -= 1461 * y / 4 ;
- y += 1984 ;
- m = (5 * n + 2) / 153 ;
- d = n - (153 * m + 2) / 5 + 1 ;
- m += 3 ;
- if (m > 12) {
- y++ ;
- m -= 12 ;
- }
- sprintf(buf, "%02d:%02d:%02d %s %d, %d",
- datetime.ds_Minute / 60, datetime.ds_Minute % 60,
- datetime.ds_Tick / 50, months[m], d, y) ;
- *s = buf;
- }
-
- /*
- * congm -- save console modes
- */
- int
- congm(void)
- {
- if (!saverr) saverr = DOSFH(2);
- return(0);
- }
-
- /*
- * CreateWindow -- create window and jam it into standard I/O
- */
- int
- CreateWindow(int esc)
- {
- char rawname[48];
- struct Screen s;
-
- if (rawcon > 0) return(0);
- congm();
-
- if (GetScreenData(&s, sizeof(s), WBENCHSCREEN, NULL) == 0) {
- s.Width = 640;
- s.Height = 200;
- }
- sprintf(rawname, "RAW:0/1/%d/%d/Kermit%s", s.Width, s.Height - 1,
- v37? "/ALT0/1/100/30" : "");
- rawcon = Open(rawname, (LONG)MODE_NEWFILE);
- if (rawcon == 0)
- return(-1);
- DOSFH(0) = DOSFH(1) = DOSFH(2) = rawcon;
-
- /* if we create a window, don't abort on errors or echo */
- backgrd = FALSE;
- ckxech = 1;
- return(0);
- }
-
- /*
- * concb -- put console in single character wakeup mode
- */
- int
- concb(char esc)
- {
- if (rawcon) return(0);
- if (CurCLI && CurProc->pr_CIS != CurCLI->cli_StandardInput)
- return(0);
- return(CreateWindow(esc));
- }
-
- /*
- * conbin -- put console in raw mode
- */
- int
- conbin(char esc)
- {
- if (rawcon) return(0);
- if (CurCLI && CurProc->pr_CIS != CurCLI->cli_StandardInput)
- return(isatty(0) ? 0 : -1);
- return(CreateWindow(esc));
- }
-
- /*
- * conres -- restore console
- * we actually restore in syscleanup()
- */
- conres()
- {
- return(0);
- }
-
- /*
- * conoc -- output character to console
- */
- int
- conoc(char c)
- {
- putchar(c);
- fflush(stdout);
- Chk_Abort();
- return c;
- }
-
- /*
- * conxo -- output x chars to console
- */
- int
- conxo(int n, char *buf)
- {
- int retval;
-
- fflush(stdout);
- retval = write(FILENO(1), buf, n);
- Chk_Abort();
- return retval;
- }
-
- /*
- * conol -- output line to console
- */
- int
- conol(char *l)
- {
- int retval;
- retval = fputs(l, stdout);
- fflush(stdout);
- Chk_Abort();
- return retval;
- }
-
- /*
- * conola -- output line array to console
- */
- int
- conola(char **l)
- {
- for (; **l; ++l)
- if (conol(*l) < 0)
- return(-1);
- return 0;
- }
-
- /*
- * conoll -- output line with CRLF
- */
- int
- conoll(char *l)
- {
- if (conol(l) < 0)
- return -1;
- if (conxo(2, "\r\n") < 0)
- return -1;
- return 0;
- }
-
- /*
- * conchk -- returns nonzero if characters available from console
- */
- int
- conchk(void)
- {
- fflush(stdout);
- Chk_Abort();
- return(WaitForChar(DOSFH(0), 0L) != 0);
- }
-
- /*
- * coninc -- get input character from console
- */
- int
- coninc(int timeout)
- {
- UBYTE ch;
-
- fflush(stdout);
- Chk_Abort();
- if (timeout > 0 && !WaitForChar(DOSFH(0), timeout * 1000000L))
- return(-1);
- if (read(FILENO(0), &ch, 1) < 1) return(-1);
- Chk_Abort();
- return((int)ch);
- }
-
- /*
- * T T S C A R R -- Copy desired character mode to global ttcarr for future
- * and later use.
- */
- ttscarr(carrier) int carrier; {
- ttcarr = carrier;
- debug(F101, "ttscarr","",ttcarr);
- return(ttcarr);
- }
-
- static int
- sendbreak(long time) {
- if (!serialopen) return(-1);
- /* flush queued output */
- TerminateWrite(1);
- nttoq = 0;
- pendwrite = TRUE;
- WriteIOB->IOSer.io_Command = SDCMD_SETPARAMS;
- WriteIOB->io_BrkTime = time;
- (void) DoIO((IOR *)WriteIOB);
- pendwrite = TRUE;
- WriteIOB->IOSer.io_Command = SDCMD_BREAK;
- WriteIOB->io_SerFlags &= ~SERF_QUEUEDBRK;
- SendIO((IOR *)WriteIOB);
- return(0);
- }
-
- /*
- * ttsndb -- send a BREAK
- * flushes queued and active output
- */
- int
- ttsndb(void)
- {
- return(sendbreak(275000L));
- }
-
- /*
- * ttsndlb -- send a long BREAK (1.5 sec)
- */
- int
- ttsndlb(void) {
- return(sendbreak(1500000L));
- }
-
- /* T T W M D M -- Wait for modem signals */
-
- /*
- Wait up to timo seconds for all of the given modem signals to appear.
- mdmsig is a bit mask, in which:
- BM_CTS (bit 0) means wait for Clear To Send
- BM_DSR (bit 1) means wait for Data Set Ready
- BM_DCD (bit 2) means wait for Carrier Detect
- Returns:
- -3 Not implemented.
- -2 This line does not have modem control.
- -1 Timeout: time limit exceeded before all signals were detected.
- 1 Success.
- */
- int
- ttwmdm(int mdmsig, int timo) {
- return(-3);
- }
-
- /* T T G M D M -- Get modem signals */
- /*
- Looks for the modem signals CTS, DSR, and CTS, and returns those that are
- on in as its return value, in a bit mask as described for ttwmdm. Returns:
- -3 Not implemented
- -2 if the line does not have modem control
- -1 on error.
- >= 0 on success, with a bit mask containing the modem signals that are on.
- */
-
- int
- ttgmdm(void) {
- return(-3);
- }
-
-
- /*
- * ttocq -- write char to serial device, queueing if necessary
- * returns -2 on overrun, -1 on serial error
- * use only in connect mode
- */
- int
- ttocq(char c)
- {
- int i;
-
- if (!serialopen) return(-1);
- if (pendwrite && CheckIO((IOR *)WriteIOB))
- {
- pendwrite = FALSE;
- if (WaitIO((IOR *)WriteIOB) != 0) return(-1);
- }
- if (pendwrite)
- {
- if (nttoq >= NTTOQ) return(-2); /* overrun */
- ttoq[(pttoq + nttoq++) % NTTOQ] = c;
- }
- else if (nttoq == 0)
- return(ttoc(c));
- else
- {
- i = ttoc(ttoq[pttoq]);
- ttoq[(pttoq + nttoq) % NTTOQ] = c;
- pttoq = (pttoq + 1) % NTTOQ;
- if (i < 0) return(-1);
- }
- return(1);
- }
-
- /*
- * ttonq -- returns number of characters in serial output queue
- */
- int
- ttonq(void)
- {
- return(nttoq);
- }
-
- /*
- * conttb -- prepare for contti() usage
- */
- void
- conttb(void)
- {
- /* flush queued input and output */
- queuedcon = -1;
- pttoq = nttoq = 0;
- }
-
- /*
- * contte -- end contti() usage
- * this can be called after a tthang, it which case ttres will already
- * have done this cleanup
- */
- void
- contte(void)
- {
- /* clear any pending ^C, ^D interrupts */
- Chk_Abort();
-
- /* terminate any pending I/O */
- if (serialopen) SerialReset();
- }
-
- /*
- * contti -- wait for console or tty input
- * returns next console input or -1 when serial input available
- */
- int
- contti(void)
- {
- int i;
- LONG waitsigs;
- struct DosPacket *pkt = conpkt;
- struct IOExtSer *myread = ReadIOB;
- static UBYTE conchar;
- BPTR dosfh = DOSFH(0);
- struct FileHandle *fh = (struct FileHandle *)BADDR(dosfh);
-
- if (queuedcon >= 0)
- {
- conchar = queuedcon;
- queuedcon = -1;
- return((int)conchar);
- }
-
- if (!pendconsole)
- { /* start a console read */
- pkt->dp_Port = conport;
- pkt->dp_Type = ACTION_READ;
- pkt->dp_Arg1 = (LONG)dosfh;
- pkt->dp_Arg2 = (LONG)&conchar;
- pkt->dp_Arg3 = 1;
- PutMsg(fh->fh_Process, pkt->dp_Link);
- pendconsole = TRUE;
- }
-
- if (queuedser < 0 && !pendread)
- { /* start a serial read */
- myread->IOSer.io_Command = CMD_READ;
- myread->IOSer.io_Data = (APTR)&serbufc;
- myread->IOSer.io_Length = 1;
- SendIO((IOR *)myread);
- pendread = TRUE;
- }
-
- waitsigs = (1L << serport->mp_SigBit) | (1L << conport->mp_SigBit);
- for (;;)
- {
- if (pendwrite && CheckIO((IOR *)WriteIOB))
- {
- WaitIO((IOR *)WriteIOB);
- pendwrite = FALSE;
- if (nttoq > 0)
- {
- i = ttoc(ttoq[pttoq]);
- pttoq = (pttoq + 1) % NTTOQ;
- --nttoq;
- if (i < 0) return(-1);
- }
- }
-
- /* give the console first chance */
- if (GetMsg(conport))
- {
- pendconsole = FALSE;
- if (pkt->dp_Res1 != 1) return(-1);
- /* translate CSI to ESC [ */
- if (conchar == 0x9B)
- {
- conchar = 0x1B;
- queuedcon = '[';
- }
- return((int)conchar);
- }
-
- if (queuedser >= 0) return(-2);
-
- if (CheckIO((IOR *)myread))
- return((TerminateRead() == 0) ? -2 : -1);
-
- Wait(waitsigs);
- }
- }
-
- /* P S U S P E N D -- Put current process in background. */
-
- /*
- * Even though this isn't supported on the Amiga, I return success anyway.
- * After all, the user can pop the window to the back and do something
- * else any time he wants.
- */
-
- int
- psuspend(int foo) {
- return 0;
- }
-
- /* P R I V _ functions -- all dummy on the Amiga. */
-
- int
- priv_ini(void) {
- return 0;
- }
-
-
- int
- priv_on(void) {
- return 0;
- }
-
- int
- priv_off(void) {
- return 0;
- }
-
- int
- priv_can(void) {
- return 0;
- }
-